home *** CD-ROM | disk | FTP | other *** search
/ The AGA Experience 3 / AGA Experience Volume 3 (1997)(NFA - SAdENESS)[!].iso / software / utilities / graphics / raylab / source / intersct.c < prev    next >
C/C++ Source or Header  |  1996-09-01  |  38KB  |  1,451 lines

  1. /*
  2.     name:    intersct.c
  3.  
  4.     Intersection-routines
  5.     ---------------------
  6.  
  7.     These routines will calculate the t-parameter of a line,
  8.     which corresponds to the point where the given line intersects with
  9.     the given primitive. The routines return zero (0) if no intersection
  10.     occured.
  11.  
  12.  
  13.     This source-code is part of the RayLab 1.1 package, and it is provided
  14.     for your compiling pleasure.  You may use it, change it, re-compile it
  15.     etc., as long as nobody else but you receive the changes/compilations
  16.     that you have made!
  17.  
  18.     You may not use any part(s) of this source-code for your own productions
  19.     without the permission from the author of RayLab. Please read the legal
  20.     information found in the users documentation for RayLab for more details.
  21.  
  22. */
  23.  
  24.  
  25. #include  "defs.h"
  26. #include  "extern.h"
  27.  
  28.  
  29.  
  30.  
  31. /**********************************************************************
  32.  *
  33.  *    Try all objects for intersection, and return object number
  34.  *    and intersection information.
  35.  *
  36.  **********************************************************************/
  37.  
  38. long Intersect_All_Objects(INTERSECTION *Intersct, LINE *RayLine)
  39. {
  40.     INTERSECTION TmpIntersct;
  41.     double    t, tnew;
  42.     long    i, ObjNum;
  43.  
  44.     ObjNum=-1L;
  45.  
  46.     t=-1.0;
  47.     for(i=0;i<NumObjects;i++) {
  48.         tnew=Intersect_Object(&TmpIntersct, RayLine, ObjectArray[i]);
  49.         if((tnew>EPSILON)&&((tnew<t)||(t<=EPSILON))) {
  50.         ObjNum=i;
  51.         t=tnew;
  52.         *Intersct=TmpIntersct;
  53.         }
  54.     }
  55.  
  56.     return(ObjNum);
  57. }
  58.  
  59.  
  60.  
  61. /**********************************************************************
  62.  *
  63.  *    Get (possible) intersection with a given object
  64.  *
  65.  **********************************************************************/
  66.  
  67.  
  68. double Intersect_Object(INTERSECTION *Intrsct, LINE *Line, OBJECT *Object)
  69. {
  70.     LINE    TransformedLine;
  71.     register double    t,a,b,c;
  72.     register long    i;
  73.     VECTOR    tempv;
  74.  
  75.     if(CheckForBounding(Line, Object)==TRUE) {            /* Check for boundings, if any */
  76.       TransformedLine.Origin=Line->Origin;
  77.       TransformedLine.Direction=Line->Direction;
  78.  
  79.       if(Object->Transform.NumTransforms>0) {
  80.         for(i=Object->Transform.NumTransforms-1L;i>=0L;i--) {
  81.         switch(Object->Transform.Entry[i].Type) {
  82.             case TRANSFORM_SCALE:
  83.             tempv=Object->Transform.Entry[i].Values;
  84.             a=1.0/tempv.x; b=1.0/tempv.y; c=1.0/tempv.z;
  85.             TransformedLine.Origin.x*=a; TransformedLine.Origin.y*=b; TransformedLine.Origin.z*=c;
  86.             TransformedLine.Direction.x*=a; TransformedLine.Direction.y*=b; TransformedLine.Direction.z*=c;
  87.             break;
  88.             case TRANSFORM_MOVE:
  89.             SubVector((VECTOR *)&TransformedLine.Origin,(VECTOR *)&TransformedLine.Origin,&Object->Transform.Entry[i].Values);
  90.             break;
  91.             case TRANSFORM_ROTATE:
  92.             NegVector(&tempv,&Object->Transform.Entry[i].Values);
  93.             RevRotatePoint(&TransformedLine.Origin,&tempv);
  94.             RevRotateVector(&TransformedLine.Direction,&tempv);
  95.             break;
  96.             case TRANSFORM_NONE:
  97.             default:
  98.             break;
  99.         }
  100.         }
  101.       }
  102.  
  103.       switch(Object->ShapeType) {
  104.         case SHAPE_PLANE:
  105.         t=Intersect_Plane(Intrsct, &TransformedLine, Object);
  106.         break;
  107.         case SHAPE_SPHERE:
  108.         t=Intersect_Sphere(Intrsct, &TransformedLine, Object);
  109.         break;
  110.         case SHAPE_ELLIPSOID:
  111.         t=Intersect_Ellipsoid(Intrsct, &TransformedLine, Object);
  112.         break;
  113.         case SHAPE_TRIANGLE:
  114.         t=Intersect_Triangle(Intrsct, &TransformedLine, Object);
  115.         break;
  116.         case SHAPE_TRIANGLELIST:
  117.         t=Intersect_TriangleList(Intrsct, &TransformedLine, Object);
  118.         break;
  119.         case SHAPE_BOX:
  120.         t=Intersect_Box(Intrsct, &TransformedLine, Object);
  121.         break;
  122.         case SHAPE_DISC:
  123.         t=Intersect_Disc(Intrsct, &TransformedLine, Object);
  124.         break;
  125.         case SHAPE_CYLINDER:
  126.         t=Intersect_Cylinder(Intrsct, &TransformedLine, Object);
  127.         break;
  128.         case SHAPE_CONE:
  129.         t=Intersect_Cone(Intrsct, &TransformedLine, Object);
  130.         break;
  131.         case SHAPE_TORUS:
  132.         t=Intersect_Torus(Intrsct, &TransformedLine, Object);
  133.         break;
  134.         case SHAPE_PEAK:
  135.         t=Intersect_Peak(Intrsct, &TransformedLine, Object);
  136.         break;
  137.         case SHAPE_DEOFLASKA:
  138.         t=Intersect_Deoflaska(Intrsct, &TransformedLine, Object);
  139.         break;
  140.         case SHAPE_CSG:
  141.         t=Intersect_CSG(Intrsct, &TransformedLine, Object);
  142.         break;
  143.         default:
  144.         t=0.0;
  145.         break;
  146.       }
  147.  
  148.       if(t>EPSILON) {
  149.         if(Object->Transform.NumTransforms>0) {    /* Transform intersection to its real place/orientation in space */
  150.         for(i=0L;i<Object->Transform.NumTransforms;i++) {
  151.             tempv=Object->Transform.Entry[i].Values;
  152.             switch(Object->Transform.Entry[i].Type) {
  153.             case TRANSFORM_SCALE:
  154.                 a=tempv.x; b=tempv.y; c=tempv.z;
  155.                 Intrsct->IPoint.x*=a; Intrsct->IPoint.y*=b; Intrsct->IPoint.z*=c;
  156.                 Intrsct->Normal.x*=1.0/a; Intrsct->Normal.y*=1.0/b; Intrsct->Normal.z*=1.0/c;
  157.                 break;
  158.             case TRANSFORM_MOVE:
  159.                 Intrsct->IPoint.x+=tempv.x;
  160.                 Intrsct->IPoint.y+=tempv.y;
  161.                 Intrsct->IPoint.z+=tempv.z;
  162.                 break;
  163.             case TRANSFORM_ROTATE:
  164.                 RotatePoint(&Intrsct->IPoint,&tempv);
  165.                 RotateVector(&Intrsct->Normal,&tempv);
  166.                 break;
  167.             case TRANSFORM_NONE:
  168.             default:
  169.                 break;
  170.             }
  171.         }
  172.         }
  173.         if(Object->Invert==INVERT_TRUE) {
  174.         NegVector(&Intrsct->Normal,&Intrsct->Normal);    /* "Reverse" surface */
  175.         }
  176.       }
  177.     }
  178.  
  179.     return(t);
  180. }
  181.  
  182.  
  183.  
  184. /**********************************************************************
  185.  *
  186.  *    These are the actual intersection calculation routines
  187.  *
  188.  **********************************************************************/
  189.  
  190.  
  191. double Intersect_Plane(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
  192. {
  193.     register double    t,pnx,pny,pnz,a,tmp;
  194.     double    lvx,lvy,lvz,lx0,ly0,lz0;
  195.     PLANE    *Plane;
  196.  
  197.     PlaneIntersectionAttempts++;
  198.     Plane=(PLANE *)Obj->Shape;
  199.  
  200.     lvx=Line->Direction.x; lvy=Line->Direction.y; lvz=Line->Direction.z;
  201.     lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
  202.     pnx=Plane->Normal.x; pny=Plane->Normal.y; pnz=Plane->Normal.z; a=Plane->a;
  203.  
  204.     tmp=pnx*lvx+pny*lvy+pnz*lvz;
  205.     if(tmp!=0.0) {
  206.         t=-(pnx*lx0+pny*ly0+pnz*lz0-a)/tmp;
  207.         if(t>EPSILON) {
  208.         PlaneIntersections++;
  209.         Intrsct->IPoint.x=lx0+lvx*t; Intrsct->IPoint.y=ly0+lvy*t; Intrsct->IPoint.z=lz0+lvz*t;
  210.         Intrsct->Normal.x=pnx; Intrsct->Normal.y=pny; Intrsct->Normal.z=pnz;
  211.         Intrsct->Texture=&Obj->Texture;
  212.         Intrsct->Shadow=Obj->Shadow;
  213.         }
  214.         else t=0.0;
  215.     }
  216.     else t=0.0;
  217.  
  218.     return(t);
  219. }
  220.  
  221.  
  222.  
  223. double Intersect_Sphere(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
  224. {
  225.     double    vx,vy,vz,lx0,ly0,lz0,sx0,sy0,sz0,r;
  226.  
  227.     register double    s,sroot,vxdx,vydy,vzdz,vxsqr,vysqr,vzsqr;
  228.     double    t;
  229.     double    dx,dy,dz;
  230.     double    dxsqr,dysqr,dzsqr;
  231.     double    vsum,t1,t2;
  232.     SPHERE    *Sphere;
  233.  
  234.     SphereIntersectionAttempts++;
  235.     Sphere=(SPHERE *)Obj->Shape;
  236.  
  237.     vx=Line->Direction.x; vy=Line->Direction.y; vz=Line->Direction.z;
  238.     lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
  239.     sx0=Sphere->Centre.x; sy0=Sphere->Centre.y; sz0=Sphere->Centre.z;
  240.     r=Sphere->r;
  241.  
  242.                         /* These are used more than once, */
  243.     dx=lx0-sx0; dy=ly0-sy0; dz=lz0-sz0;    /* thus much time is saved by not */
  244.     vxdx=vx*dx; vydy=vy*dy; vzdz=vz*dz;    /* performing the same operation  */
  245.     dxsqr=dx*dx; dysqr=dy*dy; dzsqr=dz*dz;    /* twice (or even more).          */
  246.     vxsqr=vx*vx; vysqr=vy*vy; vzsqr=vz*vz;
  247.  
  248.     vsum=(vxsqr+vysqr+vzsqr);
  249.  
  250.     sroot=2*(vxdx*(vydy+vzdz)+vydy*vzdz)+r*r*vsum;
  251.     sroot-=vxsqr*(dysqr+dzsqr)+vysqr*(dxsqr+dzsqr)+vzsqr*(dxsqr+dysqr);
  252.  
  253.     t=0.0;
  254.     if(sroot>=0) {
  255.         sroot=sqrt(sroot);
  256.  
  257.         s=-(vxdx+vydy+vzdz);
  258.         t1=(s+sroot)/vsum;        /* Note: vsum!=0, always */
  259.         t2=(s-sroot)/vsum;        /* Also: t2<=t1, as sroot>=0 */
  260.  
  261.         if(t2>EPSILON) t=t2;
  262.         else if(t1>EPSILON) t=t1;
  263.         if(t>EPSILON) {
  264.             SphereIntersections++;
  265.             Intrsct->IPoint.x=lx0+vx*t; Intrsct->IPoint.y=ly0+vy*t; Intrsct->IPoint.z=lz0+vz*t;
  266.             Intrsct->Normal.x=Intrsct->IPoint.x-sx0;
  267.             Intrsct->Normal.y=Intrsct->IPoint.y-sy0;
  268.             Intrsct->Normal.z=Intrsct->IPoint.z-sz0;
  269.             Intrsct->Texture=&Obj->Texture;
  270.             Intrsct->Shadow=Obj->Shadow;
  271.         }
  272.     }
  273.  
  274.     return(t);
  275. }
  276.  
  277.  
  278.  
  279. double Intersect_Ellipsoid(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
  280. {
  281.     double    vx,vy,vz,lx0,ly0,lz0,ex0,ey0,ez0,a,b,c;
  282.  
  283.     register double    sroot,asqr,bsqr,csqr,vxdx,vydy,vzdz;
  284.     double    t;
  285.     double    dx,dy,dz;
  286.     double    vxsqr,vysqr,vzsqr,dxsqr,dysqr,dzsqr;
  287.     double    r,s,t1,t2;
  288.     ELLIPSOID *Ellipsoid;
  289.  
  290.     EllipsoidIntersectionAttempts++;
  291.     Ellipsoid=(ELLIPSOID *)Obj->Shape;
  292.  
  293.     vx=Line->Direction.x; vy=Line->Direction.y; vz=Line->Direction.z;
  294.     lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
  295.     ex0=Ellipsoid->Centre.x; ey0=Ellipsoid->Centre.y; ez0=Ellipsoid->Centre.z;
  296.     a=Ellipsoid->Radius.x; b=Ellipsoid->Radius.y; c=Ellipsoid->Radius.z;
  297.  
  298.     asqr=a*a; bsqr=b*b; csqr=c*c;        /* These are used more than once, */
  299.     dx=lx0-ex0; dy=ly0-ey0; dz=lz0-ez0;    /* thus much time is saved by not */
  300.     vxdx=vx*dx; vydy=vy*dy; vzdz=vz*dz;    /* performing the same operation  */
  301.     dxsqr=dx*dx; dysqr=dy*dy; dzsqr=dz*dz;    /* twice (or even more).          */
  302.     vxsqr=vx*vx; vysqr=vy*vy; vzsqr=vz*vz;
  303.  
  304.     s=-((vxdx/asqr)+(vydy/bsqr)+(vzdz/csqr));
  305.  
  306.     sroot=csqr*(vxsqr*bsqr+vysqr*asqr)+vzsqr*asqr*bsqr;
  307.     sroot+=2*(vxdx*(csqr*vydy+bsqr*vzdz)+asqr*vydy*vzdz);
  308.     sroot-=vxsqr*(csqr*dysqr+bsqr*dzsqr);
  309.     sroot-=vysqr*(csqr*dxsqr+asqr*dzsqr);
  310.     sroot-=vzsqr*(bsqr*dxsqr+asqr*dysqr);
  311.  
  312.     t=0.0;
  313.     if(sroot>=0) {
  314.         sroot=sqrt(sroot)/(a*b*c);
  315.  
  316.         r=((vxsqr/asqr)+(vysqr/bsqr)+(vzsqr/csqr));
  317.  
  318.         t1=(s+sroot)/r;
  319.         t2=(s-sroot)/r;
  320.  
  321.         if((t1>EPSILON)&&((t1<t2)||(t2<EPSILON))) {
  322.             t=t1;
  323.             EllipsoidIntersections++;
  324.         }
  325.         else if((t2>EPSILON)&&((t2<t1)||(t1<EPSILON))) {
  326.             t=t2;
  327.             EllipsoidIntersections++;
  328.         }
  329.         if(t>EPSILON) {
  330.             Intrsct->IPoint.x=lx0+vx*t; Intrsct->IPoint.y=ly0+vy*t; Intrsct->IPoint.z=lz0+vz*t;
  331.             Intrsct->Normal.x=(Intrsct->IPoint.x-ex0)/(a*a);
  332.             Intrsct->Normal.y=(Intrsct->IPoint.y-ey0)/(b*b);
  333.             Intrsct->Normal.z=(Intrsct->IPoint.z-ez0)/(c*c);
  334.             Intrsct->Texture=&Obj->Texture;
  335.             Intrsct->Shadow=Obj->Shadow;
  336.         }
  337.     }
  338.  
  339.     return(t);
  340. }
  341.  
  342.  
  343.  
  344. double Intersect_Triangle(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
  345. {
  346.     double    t,ttmp,pnx,pny,pnz;
  347.     double    lvx,lvy,lvz,lx0,ly0,lz0;
  348.     double    ui,vi,u[4],v[4];
  349.     register double un,vn,um,vm;
  350.     short    sign,count,n,m;
  351.     TRIANGLE *Triangle;
  352.  
  353.     TriangleIntersectionAttempts++;
  354.     Triangle=(TRIANGLE *)Obj->Shape;
  355.  
  356.     lvx=Line->Direction.x; lvy=Line->Direction.y; lvz=Line->Direction.z;
  357.     lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
  358.     pnx=Triangle->Normal.x; pny=Triangle->Normal.y; pnz=Triangle->Normal.z;
  359.  
  360.     t=0.0;
  361.     ttmp=pnx*lvx+pny*lvy+pnz*lvz;
  362.     if(ttmp!=0.0) {
  363.         ttmp=-(pnx*lx0+pny*ly0+pnz*lz0-Triangle->Offset)/ttmp;
  364.         if(ttmp>EPSILON) {
  365.         switch(Triangle->Projection) {    /* Transform to 2D coordinates */
  366.             case PROJ_YZ:
  367.             ui=ly0+ttmp*lvy;
  368.             vi=lz0+ttmp*lvz;
  369.             break;
  370.             case PROJ_XZ:
  371.             ui=lx0+ttmp*lvx;
  372.             vi=lz0+ttmp*lvz;
  373.             break;
  374.             case PROJ_XY:
  375.             ui=lx0+ttmp*lvx;
  376.             vi=ly0+ttmp*lvy;
  377.             break;
  378.         }
  379.         u[0]=Triangle->Corners[0].u-ui;
  380.         u[1]=Triangle->Corners[1].u-ui;
  381.         u[2]=Triangle->Corners[2].u-ui;
  382.         v[0]=Triangle->Corners[0].v-vi;
  383.         v[1]=Triangle->Corners[1].v-vi;
  384.         v[2]=Triangle->Corners[2].v-vi;
  385.  
  386.         u[3]=u[0]; v[3]=v[0];
  387.         count=0;            /* Determine amount of sides crossed */
  388.         for(n=0;n<3;n++) {
  389.             m=n+1;
  390.             vn=v[n]; vm=v[m];
  391.             if(vn>=0.0) sign=1;  else sign=-1;
  392.             if(vm>=0.0) sign+=1; else sign-=1;
  393.             if(sign==0) {
  394.             un=u[n]; um=u[m];
  395.             if((un>=0.0)&&(um>=0.0)) count+=1;
  396.             else if((un>=0.0)||(um>=0.0)) {
  397.                 if((um-vm*(um-un)/(vm-vn))>0.0) count+=1;
  398.             }
  399.             }
  400.         }
  401.         if((count&0x01)==1) {    /* If odd amount of sides were crossed... */
  402.             TriangleIntersections++;
  403.             t=ttmp;
  404.             Intrsct->Normal.x=pnx;
  405.             Intrsct->Normal.y=pny;
  406.             Intrsct->Normal.z=pnz;
  407.             Intrsct->IPoint.x=lx0+lvx*t;
  408.             Intrsct->IPoint.y=ly0+lvy*t;
  409.             Intrsct->IPoint.z=lz0+lvz*t;
  410.             Intrsct->Texture=&Obj->Texture;
  411.             Intrsct->Shadow=Obj->Shadow;
  412.         }
  413.         }
  414.     }
  415.  
  416.     return(t);
  417. }
  418.  
  419.  
  420.  
  421. double Intersect_TriangleList(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
  422. {
  423.     double    t,ttmp,pnx,pny,pnz;
  424.     double    lvx,lvy,lvz,lx0,ly0,lz0;
  425.     double    ui,vi,u[4],v[4];
  426.     register double un,vn,um,vm;
  427.     short    sign,count,n,m;
  428.     TRIANGLELIST *Triangle;
  429.  
  430.     Triangle=(TRIANGLELIST *)Obj->Shape;
  431.  
  432.     lvx=Line->Direction.x; lvy=Line->Direction.y; lvz=Line->Direction.z;
  433.     lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
  434.  
  435.     t=0.0;
  436.  
  437.     while(Triangle!=NULL) {
  438.         TriangleIntersectionAttempts++;
  439.         pnx=Triangle->Normal.x; pny=Triangle->Normal.y; pnz=Triangle->Normal.z;
  440.         ttmp=pnx*lvx+pny*lvy+pnz*lvz;
  441.         if(ttmp!=0.0) {
  442.         ttmp=-(pnx*lx0+pny*ly0+pnz*lz0-Triangle->Offset)/ttmp;
  443.         if(ttmp>EPSILON) {
  444.             switch(Triangle->Projection) {    /* Transform to 2D coordinates */
  445.             case PROJ_YZ:
  446.                 ui=ly0+ttmp*lvy;
  447.                 vi=lz0+ttmp*lvz;
  448.                 break;
  449.             case PROJ_XZ:
  450.                 ui=lx0+ttmp*lvx;
  451.                 vi=lz0+ttmp*lvz;
  452.                 break;
  453.             case PROJ_XY:
  454.                 ui=lx0+ttmp*lvx;
  455.                 vi=ly0+ttmp*lvy;
  456.                 break;
  457.             }
  458.             u[0]=Triangle->Corners[0].u-ui;
  459.             u[1]=Triangle->Corners[1].u-ui;
  460.             u[2]=Triangle->Corners[2].u-ui;
  461.             v[0]=Triangle->Corners[0].v-vi;
  462.             v[1]=Triangle->Corners[1].v-vi;
  463.             v[2]=Triangle->Corners[2].v-vi;
  464.  
  465.             u[3]=u[0]; v[3]=v[0];
  466.             count=0;            /* Determine amount of sides crossed */
  467.             for(n=0;n<3;n++) {
  468.             m=n+1;
  469.             vn=v[n]; vm=v[m];
  470.             if(vn>=0.0) sign=1;  else sign=-1;
  471.             if(vm>=0.0) sign+=1; else sign-=1;
  472.             if(sign==0) {
  473.                 un=u[n]; um=u[m];
  474.                 if((un>=0.0)&&(um>=0.0)) count+=1;
  475.                 else if((un>=0.0)||(um>=0.0)) {
  476.                 if((um-vm*(um-un)/(vm-vn))>0.0) count+=1;
  477.                 }
  478.             }
  479.             }
  480.         }
  481.  
  482.         if((count&0x01)==1) {    /* If odd amount of sides were crossed... */
  483.             if((ttmp>EPSILON)&&((t<EPSILON)||(ttmp<t))) {
  484.             TriangleIntersections++;
  485.             t=ttmp;
  486.             Intrsct->Normal.x=pnx;
  487.             Intrsct->Normal.y=pny;
  488.             Intrsct->Normal.z=pnz;
  489.             Intrsct->IPoint.x=lx0+lvx*t;
  490.             Intrsct->IPoint.y=ly0+lvy*t;
  491.             Intrsct->IPoint.z=lz0+lvz*t;
  492.             }
  493.         }
  494.         }
  495.  
  496.         Triangle=Triangle->NextTriangle;
  497.     }
  498.  
  499.     if(t>EPSILON) {
  500.         Intrsct->Texture=&Obj->Texture;
  501.         Intrsct->Shadow=Obj->Shadow;
  502.     }
  503.  
  504.     return(t);
  505. }
  506.  
  507.  
  508. double Intersect_Box(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
  509. {
  510.     register double    t,told,ttmp;
  511.     double    lvx,lvy,lvz,lx0,ly0,lz0;
  512.     register double    ipx,ipy,ipz;
  513.     POINT    ip;
  514.     VECTOR    norm;
  515.     BOX    *Box;
  516.  
  517.     BoxIntersectionAttempts++;
  518.     Box=(BOX *)Obj->Shape;
  519.  
  520.     told=-1.0;
  521.     lvx=Line->Direction.x; lvy=Line->Direction.y; lvz=Line->Direction.z;
  522.     lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
  523.  
  524.     if(lvz!=0.0) {
  525.         ttmp=(Box->Corners[0].z-lz0)/lvz;    /* xy-plane, z-min */
  526.         if(ttmp>EPSILON) {
  527.         ipx=lx0+lvx*ttmp; ipy=ly0+lvy*ttmp;
  528.         if((ipx>=Box->Corners[0].x)&&(ipx<=Box->Corners[1].x)&&(ipy>=Box->Corners[0].y)&&(ipy<=Box->Corners[1].y)) {
  529.             told=ttmp; ip.x=ipx; ip.y=ipy; ip.z=Box->Corners[0].z; norm.x=norm.y=0.0; norm.z=-1.0;
  530.         }
  531.         }
  532.         ttmp=(Box->Corners[1].z-lz0)/lvz;    /* xy-plane, z-max */
  533.         if((ttmp>EPSILON)&&((told<0.0)||(ttmp<told))) {
  534.         ipx=lx0+lvx*ttmp; ipy=ly0+lvy*ttmp;
  535.         if((ipx>=Box->Corners[0].x)&&(ipx<=Box->Corners[1].x)&&(ipy>=Box->Corners[0].y)&&(ipy<=Box->Corners[1].y)) {
  536.             told=ttmp; ip.x=ipx; ip.y=ipy; ip.z=Box->Corners[1].z; norm.x=norm.y=0.0; norm.z=1.0;
  537.         }
  538.         }
  539.     }
  540.     if(lvy!=0.0) {
  541.         ttmp=(Box->Corners[0].y-ly0)/lvy;    /* xz-plane, y-min */
  542.         if((ttmp>EPSILON)&&((told<0.0)||(ttmp<told))) {
  543.         ipx=lx0+lvx*ttmp; ipz=lz0+lvz*ttmp;
  544.         if((ipx>=Box->Corners[0].x)&&(ipx<=Box->Corners[1].x)&&(ipz>=Box->Corners[0].z)&&(ipz<=Box->Corners[1].z)) {
  545.             told=ttmp; ip.x=ipx; ip.z=ipz; ip.y=Box->Corners[0].y; norm.x=norm.z=0.0; norm.y=-1.0;
  546.         }
  547.         }
  548.         ttmp=(Box->Corners[1].y-ly0)/lvy;    /* xz-plane, y-max */
  549.         if((ttmp>EPSILON)&&((told<0.0)||(ttmp<told))) {
  550.         ipx=lx0+lvx*ttmp; ipz=lz0+lvz*ttmp;
  551.         if((ipx>=Box->Corners[0].x)&&(ipx<=Box->Corners[1].x)&&(ipz>=Box->Corners[0].z)&&(ipz<=Box->Corners[1].z)) {
  552.             told=ttmp; ip.x=ipx; ip.z=ipz; ip.y=Box->Corners[1].y; norm.x=norm.z=0.0; norm.y=1.0;
  553.         }
  554.         }
  555.     }
  556.     if(lvy!=0.0) {
  557.         ttmp=(Box->Corners[0].x-lx0)/lvx;    /* yz-plane, x-min */
  558.         if((ttmp>EPSILON)&&((told<0.0)||(ttmp<told))) {
  559.         ipy=ly0+lvy*ttmp; ipz=lz0+lvz*ttmp;
  560.         if((ipy>=Box->Corners[0].y)&&(ipy<=Box->Corners[1].y)&&(ipz>=Box->Corners[0].z)&&(ipz<=Box->Corners[1].z)) {
  561.             told=ttmp; ip.y=ipy; ip.z=ipz; ip.x=Box->Corners[0].x; norm.y=norm.z=0.0; norm.x=-1.0;
  562.         }
  563.         }
  564.         ttmp=(Box->Corners[1].x-lx0)/lvx;    /* yz-plane, x-max */
  565.         if((ttmp>EPSILON)&&((told<0.0)||(ttmp<told))) {
  566.         ipy=ly0+lvy*ttmp; ipz=lz0+lvz*ttmp;
  567.         if((ipy>=Box->Corners[0].y)&&(ipy<=Box->Corners[1].y)&&(ipz>=Box->Corners[0].z)&&(ipz<=Box->Corners[1].z)) {
  568.             told=ttmp; ip.y=ipy; ip.z=ipz; ip.x=Box->Corners[1].x; norm.y=norm.z=0.0; norm.x=1.0;
  569.         }
  570.         }
  571.     }
  572.  
  573.     if(told>EPSILON) {
  574.         t=told;
  575.         BoxIntersections++;
  576.         Intrsct->IPoint=ip;
  577.         Intrsct->Normal=norm;
  578.         Intrsct->Texture=&Obj->Texture;
  579.         Intrsct->Shadow=Obj->Shadow;
  580.     }
  581.     else t=0.0;
  582.  
  583.     return(t);
  584. }
  585.  
  586.  
  587. double Intersect_Disc(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
  588. {
  589.     register double    t;
  590.  
  591.     DiscIntersectionAttempts++;
  592.  
  593.     t=Intersect_DiscShape(Intrsct, Line, (DISC *)Obj->Shape);
  594.     if(t>EPSILON) {
  595.         Intrsct->Texture=&Obj->Texture;
  596.         Intrsct->Shadow=Obj->Shadow;
  597.     }
  598.  
  599.     return(t);
  600. }
  601.  
  602.  
  603. double Intersect_DiscShape(INTERSECTION *Intrsct, LINE *Line, DISC *Disc)
  604. {
  605.     register double    t,pnx,pny,pnz,a,tmp;
  606.     double    lvx,lvy,lvz,lx0,ly0,lz0,dx,dy,dz;
  607.     POINT    ip;
  608.  
  609.     lvx=Line->Direction.x; lvy=Line->Direction.y; lvz=Line->Direction.z;
  610.     lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
  611.     pnx=Disc->Plane.Normal.x; pny=Disc->Plane.Normal.y; pnz=Disc->Plane.Normal.z; a=Disc->Plane.a;
  612.  
  613.     t=0.0;
  614.     tmp=pnx*lvx+pny*lvy+pnz*lvz;
  615.     if(tmp!=0.0) {
  616.         tmp=-(pnx*lx0+pny*ly0+pnz*lz0-a)/tmp;
  617.         if(tmp>EPSILON) {
  618.             ip.x=lx0+lvx*tmp; ip.y=ly0+lvy*tmp; ip.z=lz0+lvz*tmp;
  619.             dx=ip.x-Disc->Centre.x;
  620.             dy=ip.y-Disc->Centre.y;
  621.             dz=ip.z-Disc->Centre.z;
  622.             if((dx*dx+dy*dy+dz*dz)<(Disc->r*Disc->r)) {
  623.                 t=tmp;
  624.                 DiscIntersections++;
  625.                 Intrsct->IPoint=ip;
  626.                 Intrsct->Normal.x=pnx; Intrsct->Normal.y=pny; Intrsct->Normal.z=pnz; 
  627.             }
  628.         }
  629.     }
  630.  
  631.     return(t);
  632. }
  633.  
  634.  
  635. double Intersect_Cylinder(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
  636.     register double lvx,lvy,l0x,l0y,lvx2plvy2;
  637.     double    rsqr,a,b,c,t,t1,t2,z1,z2;
  638.     int    sidehit;
  639.     CYLINDER *Cylinder;
  640.  
  641.     CylinderIntersectionAttempts++;
  642.     Cylinder=(CYLINDER *)Obj->Shape;
  643.  
  644.     lvx=Line->Direction.x; lvy=Line->Direction.y;
  645.     l0x=Line->Origin.x; l0y=Line->Origin.y;
  646.     rsqr=Cylinder->r; rsqr*=rsqr;
  647.     lvx2plvy2=1.0/(lvx*lvx+lvy*lvy);
  648.  
  649.     a=(rsqr-l0x*l0x-l0y*l0y)*lvx2plvy2;
  650.     b=(lvx*l0x+lvy*l0y)*lvx2plvy2;
  651.     c=a+b*b;
  652.     t=0.0;
  653.     if(c>=0.0) {
  654.         c=sqrt(c);
  655.         t1=-b-c;    /*  t1 <= t2  */
  656.         t2=-b+c;
  657.         z1=z2=Line->Origin.z;
  658.         z1+=Line->Direction.z*t1;
  659.         z2+=Line->Direction.z*t2;
  660.         a=Cylinder->h;        /* a = height of cylinder */
  661.         sidehit=FALSE;
  662.         if(t1>EPSILON) {
  663.             if((z1>=0.0)&&(z1<=a)) {
  664.             t=t1;
  665.             Intrsct->IPoint.z=z1;
  666.             sidehit=TRUE;
  667.             }
  668.         }
  669.         else if(t2>EPSILON) {
  670.             if((z2>=0.0)&&(z2<=a)) {
  671.             t=t2;
  672.             Intrsct->IPoint.z=z2;
  673.             sidehit=TRUE;
  674.             }
  675.         }
  676.         b=Line->Origin.z; c=1.0/Line->Direction.z;
  677.         t1=(0.0-b)*c;            /* t1 <=> bottom hit */
  678.         t2=(a-b)*c;            /* t2 <=> top hit */
  679.         if(t1>EPSILON) {
  680.             b=l0x+lvx*t1; c=l0y+lvy*t1;
  681.             if((b*b+c*c)>rsqr) t1=0.0;        /* Outside of the cyliunder? */
  682.         }
  683.         if(t2>EPSILON) {
  684.             if((t1>EPSILON)&&(t1<t2)) t2=0.0;
  685.             else {
  686.             b=l0x+lvx*t2; c=l0y+lvy*t2;
  687.             if((b*b+c*c)>rsqr) t2=0.0;
  688.             else t1=0.0;
  689.             }
  690.         }
  691.         if((t1>EPSILON)&&((t1<t)||(t<EPSILON))) {
  692.             t=t1;
  693.             CreatePoint(&Intrsct->IPoint,l0x+lvx*t1,l0y+lvy*t1,0.0);
  694.             CreateVector(&Intrsct->Normal,0.0,0.0,-1.0);
  695.             sidehit=FALSE;
  696.         }
  697.         else if((t2>EPSILON)&&((t2<t)||(t<EPSILON))) {
  698.             t=t2;
  699.             CreatePoint(&Intrsct->IPoint,b,c,a);
  700.             CreateVector(&Intrsct->Normal,0.0,0.0,1.0);
  701.             sidehit=FALSE;
  702.         }
  703.         if(sidehit==TRUE) {
  704.             Intrsct->Normal.x=Intrsct->IPoint.x=l0x+lvx*t;
  705.             Intrsct->Normal.y=Intrsct->IPoint.y=l0y+lvy*t;
  706.             Intrsct->Normal.z=0.0;
  707.         }
  708.         if(t>=EPSILON) {
  709.             CylinderIntersections++;
  710.             Intrsct->Texture=&Obj->Texture;
  711.             Intrsct->Shadow=Obj->Shadow;
  712.         }
  713.     }
  714.  
  715.     return(t);
  716. }
  717.  
  718.  
  719. double Intersect_Cone(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
  720.     double    lvx,lvy,lvz,l0x,l0y,l0z;
  721.     double    r1,r2,h,A,B,C,a,b,c,t,t1,t2,x,y,z;
  722.     int    sidehit;
  723.     CONE    *Cone;
  724.  
  725.     ConeIntersectionAttempts++;
  726.     Cone=(CONE *)Obj->Shape;
  727.  
  728.     t = 0.0;
  729.  
  730.     r1 = Cone->r1; r2 = Cone->r2; h = Cone->h;
  731.     lvx = Line->Direction.x; lvy = Line->Direction.y; lvz = Line->Direction.z;
  732.     l0x = Line->Origin.x; l0y = Line->Origin.y; l0z = Line->Origin.z;
  733.  
  734.     c = (r2-r1)/h;
  735.     A = (lvx*lvx + lvy*lvy - c*c*lvz*lvz);
  736.     if(A!=0.0) {
  737.         A = 1.0 / A;
  738.         B = lvx*l0x + lvy*l0y - lvz*c*(l0z*c + r1);
  739.         C = l0x*l0x + l0y*l0y - l0z*c*(l0z*c + 2.0*r1) - r1*r1;
  740.  
  741.         a = A*B;
  742.         b = a*a - A*C;
  743.         if(b>=0) {
  744.         b = sqrt(b);        /* b > 0 */
  745.         t1 = -a - b;        /* t1 < t2 */
  746.         t2 = -a + b;
  747.  
  748.         sidehit = FALSE;
  749.     /* Intersection with sides */
  750.         if(t2 > EPSILON) {
  751.             z = l0z + t2*lvz;
  752.             if((z>0.0)&&(z<h)) {
  753.             t = t2; sidehit = TRUE;
  754.             }
  755.             if(t1 > EPSILON) {
  756.             z = l0z + t1*lvz;
  757.             if((z>0.0)&&(z<h)) {
  758.                 t = t1; sidehit = TRUE;
  759.             }
  760.             }
  761.         }
  762.     /* Intersection with top/bottom */
  763.         if(lvz!=0.0) {
  764.             t1 = -l0z/lvz;  t2 = (h-l0z)/lvz;
  765.             if((t1>EPSILON)&&((t<EPSILON)||(t1<t))) {
  766.             x = l0x+lvx*t1; y = l0y+lvy*t1;
  767.             if((x*x + y*y) <= (r1*r1)) {
  768.                 t = t1; sidehit = FALSE;
  769.                 Intrsct->IPoint.x = x; Intrsct->IPoint.y = y;
  770.                 Intrsct->Normal.x = Intrsct->Normal.y = 0.0;
  771.                 Intrsct->Normal.z = -1.0;
  772.             }
  773.             }
  774.             if((t2>EPSILON)&&((t<EPSILON)||(t2<t))) {
  775.             x = l0x+lvx*t2; y = l0y+lvy*t2;
  776.             if((x*x + y*y) <= (r2*r2)) {
  777.                 t = t2; sidehit = FALSE;
  778.                 Intrsct->IPoint.x = x; Intrsct->IPoint.y = y;
  779.                 Intrsct->Normal.x = Intrsct->Normal.y = 0.0;
  780.                 Intrsct->Normal.z = 1.0;
  781.             }
  782.             }
  783.         }
  784.         if(t>EPSILON) {
  785.             ConeIntersections++;
  786.             Intrsct->IPoint.z = l0z+lvz*t;
  787.             if(sidehit == TRUE) {
  788.             x = Intrsct->IPoint.x = Intrsct->Normal.x = l0x+lvx*t;
  789.             y = Intrsct->IPoint.y = Intrsct->Normal.y = l0y+lvy*t;
  790.             Intrsct->Normal.z = -sqrt(x*x + y*y)*c;
  791.             }
  792.             Intrsct->Texture = &Obj->Texture;
  793.             Intrsct->Shadow = Obj->Shadow;
  794.         }
  795.         }
  796.     }
  797.  
  798.     return(t);
  799. }
  800.  
  801.  
  802. double Torus_Function(double t, double r0, double r1, LINE *Line)
  803. {
  804.     register double    a,b,c,f;
  805.  
  806.     a=Line->Origin.x+Line->Direction.x*t;
  807.     b=Line->Origin.y+Line->Direction.y*t;
  808.     c=Line->Origin.z+Line->Direction.z*t;
  809.  
  810.     f = sqrt(a*a + b*b) - r0;
  811.     f = f*f + c*c - r1*r1;
  812.  
  813.     return(f);
  814. }
  815.  
  816.  
  817. double Torus_Derivata(double t, double r0, LINE *Line)
  818. {
  819.     register double    a,b,c,df;
  820.  
  821.     a=Line->Origin.x+Line->Direction.x*t;
  822.     b=Line->Origin.y+Line->Direction.y*t;
  823.     c=Line->Origin.z+Line->Direction.z*t;
  824.  
  825.     df = (1.0 - r0/sqrt(a*a + b*b))*(a + b);
  826.     df *= (Line->Direction.x + Line->Direction.y);
  827.     df += c*Line->Direction.z;
  828.     df += df;
  829.  
  830.     return(df);
  831. }
  832.  
  833. double Intersect_Torus(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
  834. {
  835.     register double    r0,r1,tn,fn,tb,fb,diff;
  836.     double    tnp1,fnp1;
  837.     double    dx,dy,dz,x0,y0,z0;
  838.     double    cylr,tcyl1o,tcyl2o,tcyl1i,tcyl2i,tpln1,tpln2,z1,z2,pr1,pr2;
  839.     double    dx2pdy2,a,b,c,ts[6],t;
  840.     int    i,tamount,sortchange,FoundHit;
  841.     TORUS    *Torus;
  842.  
  843.     TorusIntersectionAttempts++;
  844.     Torus=(TORUS *)Obj->Shape;
  845.  
  846.     dx=Line->Direction.x; dy=Line->Direction.y; dz=Line->Direction.z;
  847.     x0=Line->Origin.x; y0=Line->Origin.y; z0=Line->Origin.z;
  848.     r0=Torus->r0; r1=Torus->r1;
  849.     dx2pdy2=1.0/(dx*dx+dy*dy);
  850.  
  851.     cylr=(r0+r1);        /* Check for outer cylinder-bounding */
  852.     a=(cylr*cylr-x0*x0-y0*y0)*dx2pdy2;
  853.     b=(dx*x0+dy*y0)*dx2pdy2;
  854.     c=a+b*b;
  855.  
  856.     t=0.0;
  857.     if(c>=0.0) {        /* If found cylinder, try the rest */
  858.         c=sqrt(c);
  859.         tcyl1o=-b-c;    /*  tcyl1o < tcyl2o */
  860.         tcyl2o=-b+c;
  861.         if(tcyl2o>EPSILON) {  /* Don't do anything if BOTH hits behind */
  862.         z1=(z0+dz*tcyl1o);
  863.         z2=(z0+dz*tcyl2o);
  864.         if(!(((z1>r1)&&(z2>r1))||((z1<-r1)&&(z2<-r1)))) {
  865.             if(fabs(z1)>r1) tcyl1o=0.0;
  866.             if(fabs(z2)>r1) tcyl2o=0.0;
  867.             cylr=(r0-r1);      /* Check for inner cylinder */
  868.             a=(cylr*cylr-x0*x0-y0*y0)*dx2pdy2;
  869.             b=(dx*x0+dy*y0)*dx2pdy2;
  870.             c=a+b*b;
  871.             if(c>=0.0) {
  872.             c=sqrt(c);
  873.             tcyl1i=-b-c;    /*  tcyl1i < tcyl2i */
  874.             tcyl2i=-b+c;
  875.             z1=(z0+dz*tcyl1i);
  876.             z2=(z0+dz*tcyl2i);
  877.             if(fabs(z1)>r1) tcyl1i=0.0;
  878.             if(fabs(z2)>r1) tcyl2i=0.0;
  879.             }
  880.             else {
  881.             tcyl1i=tcyl2i=0.0;
  882.             }
  883.             tpln1=(r1-z0)/dz;    /* Check for plane intersection */
  884.             tpln2=(-r1-z0)/dz;
  885.             a=x0+dx*tpln1; b=y0+dy*tpln1; pr1=sqrt(a*a+b*b);
  886.             a=x0+dx*tpln2; b=y0+dy*tpln2; pr2=sqrt(a*a+b*b);
  887.             if((pr1>(r0+r1))||(pr1<(r0-r1))) tpln1=0.0;
  888.             if((pr2>(r0+r1))||(pr2<(r0-r1))) tpln2=0.0;
  889.             if( (tcyl1o>EPSILON)||(tcyl2o>EPSILON)||
  890.             (tcyl1i>EPSILON)||(tcyl2i>EPSILON)||
  891.             (tpln1>EPSILON)||(tpln2>EPSILON) ) {
  892.             tamount=0;
  893.             if(fabs(tcyl1o)>EPSILON) ts[tamount++]=tcyl1o;
  894.             if(fabs(tcyl2o)>EPSILON) ts[tamount++]=tcyl2o;
  895.             if(fabs(tcyl1i)>EPSILON) ts[tamount++]=tcyl1i;
  896.             if(fabs(tcyl2i)>EPSILON) ts[tamount++]=tcyl2i;
  897.             if(fabs(tpln1)>EPSILON)  ts[tamount++]=tpln1;
  898.             if(fabs(tpln2)>EPSILON)  ts[tamount++]=tpln2;
  899.             if(((tamount&1)!=0)||(tamount>4)) {
  900.                 tamount=-1;
  901.             }
  902.             else {
  903.                 sortchange=1;
  904.                 while(sortchange>0) {  /* Sort bound-hits */
  905.                 sortchange=0;       /* (closest last)  */
  906.                 for(i=0;i<tamount-1;i++) {
  907.                     if(ts[i+1]>ts[i]) {
  908.                     a=ts[i]; ts[i]=ts[i+1]; ts[i+1]=a;
  909.                     sortchange++;
  910.                     }
  911.                 }
  912.                 }
  913.                 a=ts[1];
  914.                 if(tamount>2) {
  915.                  b=ts[2]; c=ts[3];
  916.                 }
  917.                 ts[1]=(ts[0]+a)*0.5; ts[2]=a;
  918.                 tamount++;
  919.                 if(tamount>3) {
  920.                 ts[3]=b; ts[4]=(b+c)*0.5; ts[5]=c;
  921.                 tamount++;
  922.                 }
  923.             }
  924.             FoundHit=FALSE;
  925.             while((tamount>=2)&&(FoundHit==FALSE)) {
  926.                 tb=ts[tamount-2];    /* tb is further away than... */
  927.                 tn=ts[tamount-1];    /* ...tn  */
  928.                 fb=Torus_Function(tb,r0,r1,Line);
  929.                 fn=Torus_Function(tn,r0,r1,Line);
  930.                 if(((fn<0.0)&&(fb>0.0))||((fn>0.0)&&(fb<0.0))) {
  931.                 if((tb>EPSILON)||(tn>EPSILON)) {
  932.                     i=0; diff=1.0;    /* Trapets-method */
  933.                     while((diff>NUMEPSILON)&&(i<10)) {
  934.                     tnp1=tn-fn*(tb-tn)/(fb-fn);
  935.                     diff=fabs(tnp1-tn);
  936.                     if(diff>NUMEPSILON) {
  937.                         fnp1=Torus_Function(tnp1,r0,r1,Line);
  938.                         if(((fnp1<0.0)&&(fb<0.0))||((fnp1>0.0)&&(fb>0.0))) {
  939.                         fb=fn; tb=tn;    /* Switch direction */
  940.                         }
  941.                         fn=fnp1;
  942.                         i++;
  943.                     }
  944.                     tn=tnp1;
  945.                     }
  946.                     if(tn>NUMEPSILON) {
  947.                     FoundHit=TRUE;
  948.                     }
  949.                 }
  950.                 }
  951.                 else {            /* Newton-Raphson */
  952.                 if((tamount==2)||(tamount==5)) {
  953.                     tn=tb; fn=fb;
  954.                 }
  955.                 i=0; diff=1.0;
  956.                 while((diff>NUMEPSILON)&&(i<6)) {
  957.                     diff=fn/Torus_Derivata(tn,r0,Line);
  958.                     tn-=diff;
  959.                     diff=fabs(diff);
  960.                     if(diff>NUMEPSILON) {
  961.                     fn=Torus_Function(tn,r0,r1,Line);
  962.                     i++;
  963.                     }
  964.                 }
  965.                 if((diff<=NUMEPSILON)&&(tn>NUMEPSILON)) {
  966.                     FoundHit=TRUE;
  967.                 }
  968.                 }
  969.                 if(FoundHit==FALSE) {
  970.                 tamount--;
  971.                 if(tamount==4) tamount--;
  972.                 }
  973.             }
  974.             if(FoundHit==TRUE) {
  975.                 TorusIntersections++;
  976.                 t=tn;
  977.                 Intrsct->Texture=&Obj->Texture;
  978.                 Intrsct->Shadow=Obj->Shadow;
  979.                 Intrsct->IPoint.x=x0+dx*t;
  980.                 Intrsct->IPoint.y=y0+dy*t;
  981.                 Intrsct->IPoint.z=z0+dz*t;
  982.                 a=Intrsct->IPoint.x; b=Intrsct->IPoint.y;
  983.                 c=1.0-r0/sqrt(a*a+b*b);
  984.                 Intrsct->Normal.x=a*c;
  985.                 Intrsct->Normal.y=b*c;
  986.                 Intrsct->Normal.z=Intrsct->IPoint.z;
  987.             }
  988.             }
  989.         }
  990.         }
  991.     }
  992.  
  993.     return(t);
  994. }
  995.  
  996.  
  997. double Peak_Function(double t, LINE *Line)
  998. {
  999.     register double x,y,z,f;
  1000.  
  1001.     x = Line->Origin.x + Line->Direction.x*t;
  1002.     y = Line->Origin.y + Line->Direction.y*t;
  1003.     z = Line->Origin.z + Line->Direction.z*t;
  1004.  
  1005.     f = x*x + y*y;
  1006.     if(z>0.0) f -= 1.0/(z*z);
  1007.     else f += 1.0/(z*z);
  1008.  
  1009.     return( f );
  1010. }
  1011.  
  1012. double Peak_Derivata(double t, LINE *Line)
  1013. {
  1014.     register double x,y,z,f;
  1015.  
  1016.     x = Line->Origin.x + Line->Direction.x*t;
  1017.     y = Line->Origin.y + Line->Direction.y*t;
  1018.     z = Line->Origin.z + Line->Direction.z*t;
  1019.  
  1020.     f = x*Line->Direction.x + y*Line->Direction.y;
  1021.     if(z>0.0) f += Line->Direction.z/(z*z*z);
  1022.     else f -= Line->Direction.z/(z*z*z);
  1023.  
  1024.     return( 2.0*f );
  1025. }
  1026.  
  1027. double Intersect_Peak(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
  1028. {
  1029.     double        lvx,lvy,lvz,lx0,ly0,lz0;
  1030.     double        t,t_a,t_b,f1,f2,tnp1,fnp1,fprim;
  1031.     register double    A,B,C,D,a,b;
  1032.     int        i;
  1033.  
  1034.     PeakIntersectionAttempts++;
  1035.  
  1036.     lvx = Line->Direction.x; lvy = Line->Direction.y; lvz = Line->Direction.z;
  1037.     lx0 = Line->Origin.x; ly0 = Line->Origin.y; lz0 = Line->Origin.z;
  1038.  
  1039.     a = 1.0/lvx; b = 1.0/lvy;
  1040.     t_a = -(ly0*a+lx0*b)/(lvy*a+lvx*b);    /* Closest point to z-axis */
  1041.     t_b = -lz0/lvz;                /* Intersection with z=0 */
  1042.  
  1043.  
  1044.   /* Use Newton-Raphson to find hit with "floor" */
  1045.     tnp1 = t_b; b = 1.0; i=0;
  1046.     tnp1 = 0.0;
  1047.     while((fabs(b)>NUMEPSILON)&&((i++)<6)) {
  1048.         b = Peak_Function(tnp1,Line) / Peak_Derivata(tnp1,Line);
  1049.         tnp1 -= b;
  1050.     }
  1051.     t_b = tnp1;                /* t_b = intersection with "floor" */
  1052.  
  1053.  
  1054.  /*    a = t_a;
  1055.     f1 = D + C*a;
  1056.     a *= t_a; f1 += B*a;
  1057.     a *= t_a; f1 += A*a; */            /* f1 = f(t_a) */
  1058.  
  1059.  /*    if(f1>0.0) !utanför! */
  1060.  
  1061.     t = t_b;
  1062.  
  1063.     if(t>(NUMEPSILON*4.0)) {
  1064.         PeakIntersections++;
  1065.         a = lx0 + lvx*t; b = ly0 + lvy*t;
  1066.         Intrsct->IPoint.x=a; Intrsct->Normal.x=a;
  1067.         Intrsct->IPoint.y=b; Intrsct->Normal.y=b;
  1068.         a = lz0 + lvz*t;
  1069.         Intrsct->IPoint.z=a; Intrsct->Normal.y=1.0/(a*a*a);
  1070.         NormalizeVector(&Intrsct->Normal,&Intrsct->Normal); /* Can be _HUGE_ and _SMALL_! */
  1071.         Intrsct->Texture = &Obj->Texture;
  1072.         Intrsct->Shadow = Obj->Shadow;
  1073.     }
  1074.     else t = 0.0;
  1075.  
  1076.     return(t);
  1077. }
  1078.  
  1079.  
  1080. double Intersect_Deoflaska(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
  1081. {
  1082.     register double    t,r0,dr,h,tn,tnp1,t1,t2,diff;
  1083.     double    dx,dy,dz,x0,y0,z0,unitdz;
  1084.     double    tcyl1,tcyl2,cylr,dx2pdy2,a,b,c,z1,z2;
  1085.     int    i, MultiplePeriods, LastCheck, FoundHit;
  1086.     DEOFLASKA    *Deo;
  1087.  
  1088.     DeoflaskaIntersectionAttempts++;
  1089.     Deo=(DEOFLASKA *)Obj->Shape;
  1090.  
  1091.     dx=Line->Direction.x; dy=Line->Direction.y; dz=Line->Direction.z;
  1092.     x0=Line->Origin.x; y0=Line->Origin.y; z0=Line->Origin.z;
  1093.     r0=Deo->r0; dr=Deo->dr; h=Deo->h;
  1094.  
  1095.     cylr=(r0+dr)*1.03;    /* Check for cylinder-bounding */
  1096.     dx2pdy2=1.0/(dx*dx+dy*dy);
  1097.  
  1098.     a=(cylr*cylr-x0*x0-y0*y0)*dx2pdy2;
  1099.     b=(dx*x0+dy*y0)*dx2pdy2;
  1100.     c=a+b*b;
  1101.  
  1102.     if(c>=0.0) {        /* If found cylinder, try numerical root-finding */
  1103.         c=sqrt(c);
  1104.         tcyl1=-b-c;        /*  tcyl1 < tcyl2 */
  1105.         tcyl2=-b+c;
  1106.         if(tcyl2>EPSILON) {    /* Don't do anything if BOTH hits behind */
  1107.         FoundHit=FALSE;
  1108.         LastCheck=FALSE;
  1109.         if(((dz*dz)/(dx*dx+dy*dy))>0.25) MultiplePeriods=TRUE;
  1110.         else MultiplePeriods=FALSE;
  1111.         t1=t2=tcyl1;
  1112.         unitdz=fabs(dz)/sqrt(dx*dx+dy*dy+dz*dz);
  1113.         while((FoundHit==FALSE)&&(LastCheck==FALSE)) {
  1114.             t1=t2;        /* Determine interval t1 <= t <= t2 containing max one root */
  1115.             if(MultiplePeriods==TRUE) {
  1116.             z1=(z0+dz*t1);
  1117.             if(dz>0.0) {
  1118.                 z2=(floor((z1+PID2)/PI)*PI)+PID2;
  1119. /*                z2=floor((z1+PI)/PI)*PI; */
  1120.                 if((z2-z1)<EPSILON) z2+=PI;
  1121.             } else {
  1122.                 z2=(floor((z1-PID2)/PI)*PI)+PID2;
  1123. /*                z2=floor(z1/PI)*PI; */
  1124.                 if((z1-z2)<EPSILON) z2-=PI;
  1125.             }
  1126.             t2=(z2-z0)/dz;
  1127.             if(t2>=tcyl2) {
  1128.                 t2=tcyl2;
  1129.                 LastCheck=TRUE;
  1130.             }
  1131.             tn=(t1+t2)*0.5;    /* Start in the middle of the interval */
  1132.             }
  1133.             else {
  1134.             if(t2<=(tcyl1+NUMEPSILON)) {
  1135.                 t1=tcyl1;
  1136.                 t2=(tcyl1+tcyl2)*0.5;
  1137.                 tn=tcyl1;
  1138.             }
  1139.             else {
  1140.                 t1=(tcyl1+tcyl2)*0.5;
  1141.                 t2=tcyl2;
  1142.                 tn=tcyl2;
  1143.                 LastCheck=TRUE;
  1144.             }
  1145.             }
  1146.  
  1147.             if(t2>EPSILON) {
  1148.             i=0; diff=1.0;
  1149.             while((diff>NUMEPSILON)&&(i<6)) {
  1150.                 a=(x0+dx*tn); b=(y0+dy*tn); c=(r0-dr*sin(z0+dz*tn));
  1151.                 diff=(a*a+b*b-c*c)/(2*a*dx+2*b*dy+2*c*dr*cos(z0+dz*tn)*dz);
  1152.                 tnp1=tn-diff;
  1153.                 diff=fabs(diff);
  1154.                 tn=tnp1;
  1155.                 i++;
  1156.             }
  1157.             if((diff<NUMEPSILON)&&(tn>(4.0*NUMEPSILON))&&(tn>=t1)&&(tn<=t2)) FoundHit=TRUE;
  1158.             else FoundHit=FALSE;
  1159.             }
  1160.         }
  1161.         if((FoundHit==TRUE)&&(tn>(4.0*NUMEPSILON))&&(tn>=tcyl1)&&(tn<=tcyl2)) {
  1162.             DeoflaskaIntersections++;
  1163.             t=tn;
  1164.             Intrsct->Texture=&Obj->Texture;
  1165.             Intrsct->Shadow=Obj->Shadow;
  1166.             Intrsct->IPoint.x=Intrsct->Normal.x=x0+dx*t;
  1167.             Intrsct->IPoint.y=Intrsct->Normal.y=y0+dy*t;
  1168.             Intrsct->IPoint.z=z0+dz*t;
  1169.             Intrsct->Normal.z=(r0-dr*sin(Intrsct->IPoint.z))*dr*cos(Intrsct->IPoint.z);
  1170.         }
  1171.         else t=0.0;
  1172.         }
  1173.         else t=0.0;
  1174.     }
  1175.     else t=0.0;
  1176.  
  1177.     return(t);
  1178. }
  1179.  
  1180.  
  1181. double Intersect_CSG(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
  1182. {
  1183.     register double    t, t1, t2, ttmp;
  1184.     short    operator, inside1, inside2, leftobj;
  1185.     INTERSECTION Intersct1, Intersct2;
  1186.     LINE    NewLine;
  1187.     CSG    *CsgObject;
  1188.  
  1189.     CsgIntersectionAttempts++;
  1190.     CsgObject=(CSG *)Obj->Shape;
  1191.  
  1192.     t=0.0; operator=CsgObject->Operator;
  1193.  
  1194.     switch(operator) {
  1195.  
  1196.  
  1197.     /* --- Logical AND (also used for MINUS) --- */
  1198.  
  1199.         case CSG_OP_AND:
  1200.         t=t1=t2=0.0;
  1201.         inside1=inside2=CSG_OUTSIDE;
  1202.  
  1203.         leftobj=FALSE;
  1204.         NewLine.Direction=Line->Direction;
  1205.         NewLine.Origin=Line->Origin;
  1206.         while((leftobj==FALSE)&&(inside1==CSG_OUTSIDE)) {
  1207.             ttmp=Intersect_Object(&Intersct1,&NewLine,CsgObject->Object1);
  1208.             if(ttmp>EPSILON) {
  1209.             t1+=ttmp;
  1210.             inside1=InsideObject(CsgObject->Object2,&Intersct1.IPoint);
  1211.             NewLine.Origin=Intersct1.IPoint;
  1212.             }
  1213.             else leftobj=TRUE;
  1214.         }
  1215.  
  1216.         leftobj=FALSE;
  1217.         NewLine.Origin=Line->Origin;
  1218.         while((leftobj==FALSE)&&(inside2==CSG_OUTSIDE)) {
  1219.             ttmp=Intersect_Object(&Intersct2,&NewLine,CsgObject->Object2);
  1220.             if(ttmp>EPSILON) {
  1221.             t2+=ttmp;
  1222.             inside2=InsideObject(CsgObject->Object1,&Intersct2.IPoint);
  1223.             NewLine.Origin=Intersct2.IPoint;
  1224.             }
  1225.             else leftobj=TRUE;
  1226.         }
  1227.  
  1228.         if((inside1==CSG_INSIDE)&&(inside2==CSG_OUTSIDE)) {
  1229.             t=t1;
  1230.             CopyIntersection(Intrsct,&Intersct1);
  1231.         }
  1232.         else if((inside1==CSG_OUTSIDE)&&(inside2==CSG_INSIDE)) {
  1233.             t=t2;
  1234.             CopyIntersection(Intrsct,&Intersct2);
  1235.         }
  1236.         else if((inside1==CSG_INSIDE)&&(inside2==CSG_INSIDE)) {
  1237.             if(t1<t2) {
  1238.             t=t1;
  1239.             CopyIntersection(Intrsct,&Intersct1);
  1240.             } else {
  1241.             t=t2;
  1242.             CopyIntersection(Intrsct,&Intersct2);
  1243.             }
  1244.         }
  1245.  
  1246.         break;
  1247.  
  1248.  
  1249.     /* --- Logical OR (single surface) --- */
  1250.  
  1251.         case CSG_OP_OR:
  1252.         t=t1=t2=0.0;
  1253.         inside1=inside2=CSG_INSIDE;
  1254.  
  1255.         leftobj=FALSE;
  1256.         NewLine.Direction=Line->Direction;
  1257.         NewLine.Origin=Line->Origin;
  1258.         while((leftobj==FALSE)&&(inside1==CSG_INSIDE)) {
  1259.             ttmp=Intersect_Object(&Intersct1,&NewLine,CsgObject->Object1);
  1260.             if(ttmp>EPSILON) {
  1261.             t1+=ttmp;
  1262.             inside1=InsideObject(CsgObject->Object2,&Intersct1.IPoint);
  1263.             NewLine.Origin=Intersct1.IPoint;
  1264.             }
  1265.             else leftobj=TRUE;
  1266.         }
  1267.  
  1268.         leftobj=FALSE;
  1269.         NewLine.Origin=Line->Origin;
  1270.         while((leftobj==FALSE)&&(inside2==CSG_INSIDE)) {
  1271.             ttmp=Intersect_Object(&Intersct2,&NewLine,CsgObject->Object2);
  1272.             if(ttmp>EPSILON) {
  1273.             t2+=ttmp;
  1274.             inside2=InsideObject(CsgObject->Object1,&Intersct2.IPoint);
  1275.             NewLine.Origin=Intersct2.IPoint;
  1276.             }
  1277.             else leftobj=TRUE;
  1278.         }
  1279.  
  1280.         if((inside1==CSG_OUTSIDE)&&(inside2==CSG_INSIDE)) {
  1281.             t=t1;
  1282.             CopyIntersection(Intrsct,&Intersct1);
  1283.         }
  1284.         else if((inside1==CSG_INSIDE)&&(inside2==CSG_OUTSIDE)) {
  1285.             t=t2;
  1286.             CopyIntersection(Intrsct,&Intersct2);
  1287.         }
  1288.         else if((inside1==CSG_OUTSIDE)&&(inside2==CSG_OUTSIDE)) {
  1289.             if(t1<t2) {
  1290.             t=t1;
  1291.             CopyIntersection(Intrsct,&Intersct1);
  1292.             } else {
  1293.             t=t2;
  1294.             CopyIntersection(Intrsct,&Intersct2);
  1295.             }
  1296.         }
  1297.  
  1298.         break;
  1299.  
  1300.  
  1301.     /* --- PLUS (closest hit, simple OR) --- */
  1302.  
  1303.         case CSG_OP_PLUS:
  1304.         t1=Intersect_Object(&Intersct1,Line,CsgObject->Object1);
  1305.         t2=Intersect_Object(&Intersct2,Line,CsgObject->Object2);
  1306.         if(t1>EPSILON) {
  1307.             if(t1<t2) t=t1;
  1308.             else if(t2>EPSILON) t=t2;
  1309.             else t=t1;
  1310.         }
  1311.         else if(t2>EPSILON) t=t2;
  1312.  
  1313.         if(t>EPSILON) {
  1314.             if(fabs(t-t1)<EPSILON) CopyIntersection(Intrsct,&Intersct1);
  1315.             else      CopyIntersection(Intrsct,&Intersct2);
  1316.         }
  1317.  
  1318.         break;
  1319.  
  1320.  
  1321.         default:
  1322.         break;
  1323.  
  1324.     }
  1325.  
  1326.     if(t>0) CsgIntersections++;
  1327.  
  1328.     return(t);
  1329. }
  1330.  
  1331.  
  1332.  
  1333. /**********************************************************************
  1334.  *
  1335.  *    Test for bounding intersections
  1336.  *
  1337.  **********************************************************************/
  1338.  
  1339. int CheckForBounding(LINE *Line, OBJECT *Obj)
  1340. {
  1341.     switch(Obj->BoundType) {
  1342.        case BOUND_BOX:
  1343.         return(CheckForBoundingBox(Line,(BOX *)Obj->Bound));
  1344.         break;
  1345.        case BOUND_SPHERE:
  1346.         return(CheckForBoundingSphere(Line,(SPHERE *)Obj->Bound));
  1347.         break;
  1348.        case BOUND_NONE:
  1349.        default:
  1350.         return(TRUE);
  1351.         break;
  1352.     }
  1353. }
  1354.  
  1355. int CheckForBoundingBox(LINE *Line, BOX *Box)
  1356. {
  1357.     register double    ttmp;
  1358.     double    lvx,lvy,lvz,lx0,ly0,lz0;
  1359.     register double    ipx,ipy,ipz;
  1360.  
  1361.     lvx=Line->Direction.x; lvy=Line->Direction.y; lvz=Line->Direction.z;
  1362.     lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
  1363.  
  1364.     if(lvz!=0.0) {
  1365.         ttmp=(Box->Corners[0].z-lz0)/lvz;    /* xy-plane, z-min */
  1366.         if(ttmp>EPSILON) {
  1367.         ipx=lx0+lvx*ttmp; ipy=ly0+lvy*ttmp;
  1368.         if((ipx>=Box->Corners[0].x)&&(ipx<=Box->Corners[1].x)&&(ipy>=Box->Corners[0].y)&&(ipy<=Box->Corners[1].y))
  1369.             return(TRUE);
  1370.         }
  1371.         ttmp=(Box->Corners[1].z-lz0)/lvz;    /* xy-plane, z-max */
  1372.         if(ttmp>EPSILON) {
  1373.         ipx=lx0+lvx*ttmp; ipy=ly0+lvy*ttmp;
  1374.         if((ipx>=Box->Corners[0].x)&&(ipx<=Box->Corners[1].x)&&(ipy>=Box->Corners[0].y)&&(ipy<=Box->Corners[1].y))
  1375.             return(TRUE);
  1376.         }
  1377.     }
  1378.     if(lvy!=0.0) {
  1379.         ttmp=(Box->Corners[0].y-ly0)/lvy;    /* xz-plane, y-min */
  1380.         if(ttmp>EPSILON) {
  1381.         ipx=lx0+lvx*ttmp; ipz=lz0+lvz*ttmp;
  1382.         if((ipx>=Box->Corners[0].x)&&(ipx<=Box->Corners[1].x)&&(ipz>=Box->Corners[0].z)&&(ipz<=Box->Corners[1].z))
  1383.             return(TRUE);
  1384.         }
  1385.         ttmp=(Box->Corners[1].y-ly0)/lvy;    /* xz-plane, y-max */
  1386.         if(ttmp>EPSILON) {
  1387.         ipx=lx0+lvx*ttmp; ipz=lz0+lvz*ttmp;
  1388.         if((ipx>=Box->Corners[0].x)&&(ipx<=Box->Corners[1].x)&&(ipz>=Box->Corners[0].z)&&(ipz<=Box->Corners[1].z))
  1389.             return(TRUE);
  1390.         }
  1391.     }
  1392.     if(lvx!=0.0) {
  1393.         ttmp=(Box->Corners[0].x-lx0)/lvx;    /* yz-plane, x-min */
  1394.         if(ttmp>EPSILON) {
  1395.         ipy=ly0+lvy*ttmp; ipz=lz0+lvz*ttmp;
  1396.         if((ipy>=Box->Corners[0].y)&&(ipy<=Box->Corners[1].y)&&(ipz>=Box->Corners[0].z)&&(ipz<=Box->Corners[1].z))
  1397.             return(TRUE);
  1398.         }
  1399.         ttmp=(Box->Corners[1].x-lx0)/lvx;    /* yz-plane, x-max */
  1400.         if(ttmp>EPSILON) {
  1401.         ipy=ly0+lvy*ttmp; ipz=lz0+lvz*ttmp;
  1402.         if((ipy>=Box->Corners[0].y)&&(ipy<=Box->Corners[1].y)&&(ipz>=Box->Corners[0].z)&&(ipz<=Box->Corners[1].z))
  1403.             return(TRUE);
  1404.         }
  1405.     }
  1406.  
  1407.     return(FALSE);
  1408. }
  1409.  
  1410.  
  1411.  
  1412. int CheckForBoundingSphere(LINE *Line, SPHERE *Sphere)
  1413. {
  1414.     double    vx,vy,vz,r;
  1415.     register double    sroot,vydy,vzdz,vxsqr,vysqr,vzsqr;
  1416.     double    dx,dy,dz;
  1417.     double    dxsqr,dysqr,dzsqr;
  1418.  
  1419.     vx=Line->Direction.x; vy=Line->Direction.y; vz=Line->Direction.z;
  1420.     r=Sphere->r;
  1421.  
  1422.     dx=Line->Origin.x-Sphere->Centre.x;
  1423.     dy=Line->Origin.y-Sphere->Centre.y;
  1424.     dz=Line->Origin.z-Sphere->Centre.z;
  1425.     vydy=vy*dy; vzdz=vz*dz;
  1426.     dxsqr=dx*dx; dysqr=dy*dy; dzsqr=dz*dz;
  1427.     vxsqr=vx*vx; vysqr=vy*vy; vzsqr=vz*vz;
  1428.  
  1429.     sroot=2*(vx*dx*(vydy+vzdz)+vydy*vzdz)+r*r*(vxsqr+vysqr+vzsqr);
  1430.     sroot-=vxsqr*(dysqr+dzsqr)+vysqr*(dxsqr+dzsqr)+vzsqr*(dxsqr+dysqr);
  1431.  
  1432.     if(sroot>=0.0) return(TRUE);
  1433.     else           return(FALSE);
  1434. }
  1435.  
  1436.  
  1437.  
  1438.  
  1439. /*  Misc. */
  1440.  
  1441. void CopyIntersection(INTERSECTION *i1, INTERSECTION *i2)
  1442. {
  1443.     i1->IPoint=i2->IPoint;
  1444.     i1->Normal=i2->Normal;
  1445.     i1->Texture=i2->Texture;
  1446.     i1->Shadow=i2->Shadow;
  1447. }
  1448.  
  1449.